package cn.com.cetccst.sdk.openapi;

import static cn.com.cetccst.sdk.channel.SSAct.PERMISSION_REGISTER;
import static cn.com.cetccst.sdk.channel.SSAct.SSAPP_APP_KEY;
import static cn.com.cetccst.sdk.channel.SSAct.SS_PACKAGE_NAME;
import static cn.com.cetccst.sdk.channel.SSAct.SS_TARGET_ACTIVITY_ENTRY;
import static cn.com.cetccst.sdk.modelbase.BaseReq.SSAPI_BASEREQ_TRANSACTION;
import static cn.com.cetccst.sdk.modelbase.ConstantsAPI.COMMAND_RECEIVE_PAYLOAD_MESSAGE;
import static cn.com.cetccst.sdk.modelbase.ConstantsAPI.COMMAND_UNKNOWN;
import static cn.com.cetccst.sdk.modelbase.ConstantsAPI.SSAPI_COMMAND_TYPE;

import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import cn.com.cetccst.sdk.R;
import cn.com.cetccst.sdk.channel.SSAct;
import cn.com.cetccst.sdk.modelbase.BaseReq;
import cn.com.cetccst.sdk.modelbase.BaseResp;
import cn.com.cetccst.sdk.modelbase.ErrorMessage;
import cn.com.cetccst.sdk.modelbiz.ReceivePayloadMessage;
import cn.com.cetccst.sdk.utils.SSAPIUtil;

public class SSApiImpl implements ISSAPI {
    private final static String TAG = SSApiImpl.class.getSimpleName();
    private static final long TRANSACTION_STAMP = 5 * 24 * 60 * 60 * 1000;
    public String TARGET_PACKAGE_NAME = SS_PACKAGE_NAME;
    protected Context context;
    protected String appKey;
    protected volatile static Map<String, IResponseListener> responseListenerMap = new HashMap<>();

    private BroadcastReceiver respReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            //因为appkey是唯一的，仅处理一次
            if (TextUtils.isEmpty(appKey) || !appKey.equals(intent.getAction())) {
                return;
            }
            final BaseResp resp = BaseResp.createRespByType(intent.getIntExtra(SSAPI_COMMAND_TYPE, COMMAND_UNKNOWN));
            resp.fromBundle(intent.getExtras());
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                public void run() {
                    handleResponseListener(resp);
                }
            });
        }
    };

    protected SSApiImpl(Context context, String appKey) {
        if (context instanceof Application) {
            this.context = context;
        } else {
            this.context = context.getApplicationContext();
        }

        String suitePackage = SSAct.getSuitePackage(context);
        if (!TextUtils.isEmpty(suitePackage)) {
            TARGET_PACKAGE_NAME = suitePackage;
        }
        SSAct.PERMISSION_REGISTER = TARGET_PACKAGE_NAME + SSAct.PERMISSION_REGISTER_SUFFIX;
        registerApp(appKey);
        SSAPIUtil.init(context.getApplicationContext());
        if (ErrorMessage.getMap() == null)
            ErrorMessage.init(context.getApplicationContext());
    }

    public void registerApp(String appKey) {

        if (TextUtils.isEmpty(appKey)) {
            Log.e(TAG, "register app failed for appKey is null");
            return;
        }
        if (appKey.equals(this.appKey)) {
            Log.e(TAG, "registered app already");
            return;
        }
        this.appKey = appKey;
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(appKey);
        if (SSAPP_APP_KEY.equals(appKey)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                context.registerReceiver(respReceiver, intentFilter, PERMISSION_REGISTER, null, Context.RECEIVER_EXPORTED);
            } else {
                context.registerReceiver(respReceiver, intentFilter, PERMISSION_REGISTER, null);
            }
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                context.registerReceiver(respReceiver, intentFilter, Context.RECEIVER_EXPORTED);
            } else {
                context.registerReceiver(respReceiver, intentFilter);
            }
        }
    }

    public void unregisterApp() {
        if (!TextUtils.isEmpty(appKey)) {
            this.appKey = null;
            context.unregisterReceiver(respReceiver);
        }
    }

    @Override
    public boolean handleIntent(Intent intent, ISSAPIEventHandler handler) {

        try {
            int type = intent.getIntExtra(SSAPI_COMMAND_TYPE, COMMAND_UNKNOWN);
            switch (type) {
                case COMMAND_RECEIVE_PAYLOAD_MESSAGE:
                    handler.onReq(new ReceivePayloadMessage.Req(intent.getExtras()));
                    break;
                default:
                    String transaction = intent.getStringExtra(SSAPI_BASEREQ_TRANSACTION);
                    BaseResp baseResp = BaseResp.createRespByType(type);
                    baseResp.transaction = transaction;
                    baseResp.errorCode = BaseResp.ErrCode.ERR_NOT_SUPPORT;
                    baseResp.errorStr = ErrorMessage.getErrorMessage(baseResp.errorCode);
                    sendResp(baseResp);
                    break;
            }
        } catch (Exception exception) {
            Log.e(TAG, "handleIntent fail, ex = " + exception.getMessage());
        }
        return false;
    }

    protected void handleResponse(BaseResp resp, ISSAPIEventHandler handler) {
        handleResponseListener(resp);
//        handler.onResp(resp);
    }

    @Override
    public boolean isSSAppInstalled() {
        try {
            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(TARGET_PACKAGE_NAME, PackageManager.GET_CONFIGURATIONS);
            return (packageInfo == null ? false : true);
        } catch (PackageManager.NameNotFoundException var2) {
            return false;
        }
    }

    @Override
    public int getSSAppSupportAPI() {
        return SSAct.getSdkVersion(context, TARGET_PACKAGE_NAME);
    }

    @Override
    public boolean openSSApp() {
        if (!isSSAppInstalled()) {
            Log.e(TAG, "open cx app failed, not installed or signature check failed");
            return false;
        } else {
            try {
                context.startActivity(context.getPackageManager().getLaunchIntentForPackage(TARGET_PACKAGE_NAME));
                return true;
            } catch (Exception exception) {
                Log.e(TAG, "startActivity fail, exception = " + exception.getMessage());
                return false;
            }
        }
    }

    protected int sendReqInner(BaseReq req) {
        if (TextUtils.isEmpty(appKey)) {
            Toast.makeText(context, context.getString(R.string.ss_opensdk_app_key_null), Toast.LENGTH_SHORT).show();
            Log.d(TAG, "appKey is null");
            return BaseResp.ErrCode.ERR_APP_KEY_NULL;
        }
        req.appKey = appKey;
        if (!req.checkArgs()) {
            Log.e(TAG, context.getString(R.string.ss_opensdk_parameter_null));
            return BaseResp.ErrCode.ERR_PARAMETER_NULL;
        } else {
            Log.i(TAG, "sendReq, req type = " + req.getType());
            Bundle bundle = new Bundle();
            req.toBundle(bundle);

            return sendReq(bundle);
        }
    }

    /**
     * 仅仅为分享提供而已，其它当然也可以，尽量加callback
     *
     * @param req
     * @return
     */
    @Override
    public boolean sendReq(BaseReq req) {
        if (sendReqInner(req) == BaseResp.ErrCode.ERR_OK) {
            return true;
        }
        return false;
    }

    protected int sendReq(Bundle bundle) {
        SSAct.Args args = getArgs(bundle);
        return SSAct.send(context, args, true);
    }

    protected SSAct.Args getArgs(Bundle bundle) {
        SSAct.Args args = new SSAct.Args();
        args.appKey = appKey;
        args.mBundle = bundle;
        args.mTargetPkgName = TARGET_PACKAGE_NAME;
        args.mTargetClassName = SS_TARGET_ACTIVITY_ENTRY;
        return args;
    }

    @Override
    public boolean sendReq(BaseReq req, IResponseListener responseListener) {
        tryToClearTrashListener();
        int resultCode = sendReqInner(req);
        boolean success = (resultCode == BaseResp.ErrCode.ERR_OK);
        if (!success) {
            responseSendFailed(req, resultCode, responseListener);
        } else {
            addResponseListener(req, responseListener);
        }
        return success;
    }

    protected void tryToClearTrashListener() {
        Iterator<Map.Entry<String, IResponseListener>> entryIterator = responseListenerMap.entrySet().iterator();
        while (entryIterator.hasNext()) {
            Map.Entry<String, IResponseListener> entry = entryIterator.next();
            if (isTransactionExpired(entry.getKey())) {
                entryIterator.remove();
            }
        }
    }

    protected boolean isTransactionExpired(String key) {
        String time = key.substring(key.lastIndexOf("_") + 1);
        if (System.currentTimeMillis() - Long.parseLong(time) > TRANSACTION_STAMP) {
            return true;
        }
        return false;
    }

    protected void addResponseListener(BaseReq req, IResponseListener responseListener) {
        if (responseListener != null) {
            responseListenerMap.put(req.transaction, responseListener);
        }
    }

    protected void responseSendFailed(BaseReq req, int errorCode, IResponseListener responseListener) {
        if (responseListener == null) {
            return;
        }
        BaseResp baseResp = BaseResp.createRespByType(req.type);

        if (baseResp != null) {
            baseResp.transaction = req.transaction;
            baseResp.errorCode = errorCode;
            baseResp.errorStr = ErrorMessage.getErrorMessage(errorCode);
            responseListener.onResponse(baseResp);
        }
    }

    @Override
    public boolean sendResp(BaseResp resp) {
        if (TextUtils.isEmpty(appKey)) {
            Log.d(TAG, "appKey is null");
            return false;
        }
        Bundle bundle = new Bundle();
        resp.toBundle(bundle);
        SSAct.Args args = new SSAct.Args();
        args.mBundle = bundle;
        args.appKey = appKey;
        return SSAct.sendBR(context, SSAPP_APP_KEY, args, PERMISSION_REGISTER);
    }

    public static void handleResponseListener(BaseResp resp) {
        IResponseListener responseListener = responseListenerMap.remove(resp.transaction);
        if (responseListener != null) {
            responseListener.onResponse(resp);
        }
    }
}
